import pandas as pd
import numpy as np
from pathlib import Path
import warnings
import os
import traceback
import re

def clean_city_name(city_name):
    """清理城市名称，去除特殊字符和空格"""
    if pd.isna(city_name):
        return None
    # 将城市名称转换为字符串
    city_name = str(city_name)
    # 去除特殊字符和空格
    cleaned = re.sub(r'[^\w\u4e00-\u9fff]', '', city_name)
    return cleaned

def safe_to_datetime(df, column):
    """安全地将列转换为datetime类型"""
    try:
        # 首先检查列是否存在
        if column not in df.columns:
            print(f"警告: 列 '{column}' 不存在")
            return df
        
        # 尝试转换为datetime，处理错误格式
        df[column] = pd.to_datetime(df[column], errors='coerce')
        
        # 检查是否有无效日期
        invalid_count = df[column].isna().sum()
        if invalid_count > 0:
            print(f"警告: '{column}' 列中有 {invalid_count} 个无效日期")
        
        return df
    except Exception as e:
        print(f"转换 '{column}' 列时出错: {str(e)}")
        return df

def format_datetime(value):
    """安全地格式化日期时间值"""
    try:
        if pd.isna(value):
            return None
        return pd.to_datetime(value).strftime('%Y-%m-%d')
    except:
        return value

def main(once = False):
    """主函数：分析出差目的地变更情况"""
    try:
        # 忽略警告
        warnings.filterwarnings('ignore')
        
        # 设置数据文件路径
        data_dir = Path("data")
        alldata_dir = data_dir / "alldata"
        
        # 确保目录存在
        alldata_dir.mkdir(parents=True, exist_ok=True)
        
        # 读取源数据
        print("正在读取源数据...")
        
        # 读取差旅费票据信息
        tickets_file = data_dir / "差旅费票据信息.xlsx"
        if not tickets_file.exists():
            raise FileNotFoundError(f"票据信息文件不存在: {tickets_file}")
        tickets_df = pd.read_excel(tickets_file)
        
        # 读取差旅报销行程明细
        travel_file = data_dir / "差旅报销行程明细(商旅).xlsx"
        if not travel_file.exists():
            raise FileNotFoundError(f"行程明细文件不存在: {travel_file}")
        travel_df = pd.read_excel(travel_file)
        
        print("正在处理数据...")
        
        # 打印列名，帮助调试
        print("\n票据信息文件的列名:", tickets_df.columns.tolist())
        print("行程明细文件的列名:", travel_df.columns.tolist())
        
        # 清理列名中的空格
        tickets_df.columns = tickets_df.columns.str.strip()
        travel_df.columns = travel_df.columns.str.strip()
        
        # 安全地转换时间列
        tickets_df = safe_to_datetime(tickets_df, '开票日期')
        travel_df = safe_to_datetime(travel_df, '出发时间')
        
        # 创建结果DataFrame
        result_rows = []
        
        # 按唯一标识和人员名称分组处理数据
        for (unique_id, emp_name), group in travel_df.groupby(['唯一标识', '人员名称']):
            # 获取该组对应的票据信息
            tickets = tickets_df[
                (tickets_df['唯一标识'] == unique_id) & 
                (tickets_df['发票人员名称'] == emp_name)
            ]
            
            if tickets.empty:
                continue  # 如果没有找到对应的票据信息，直接跳过处理下一组
            
            # 获取票据中的城市名称并清理
            ticket_cities = tickets['城市名称'].unique()
            cleaned_ticket_cities = [clean_city_name(city) for city in ticket_cities if pd.notna(city)]
            
            # 检查组内是否有任何目的地与票据城市匹配
            group_has_match = False
            for dest in group['目的地名称'].unique():
                if pd.notna(dest):
                    cleaned_dest = clean_city_name(dest)
                    if cleaned_dest in cleaned_ticket_cities:
                        group_has_match = True
                        break
            
            # 如果组内没有任何匹配，或者有日期问题，则处理每条记录
            if not group_has_match or tickets['开票日期'].min() < group['出发时间'].min():
                # 如果需要处理这组数据，才计算目的地等级
                destination_counts = None
                
                # 处理每条行程记录
                for _, row in group.iterrows():
                    city_mismatch = not group_has_match  # 根据组的匹配结果设置
                    date_early = False
                    ticket_city = None
                    ticket_date = None
                    
                    if not group_has_match:
                        print("城市匹配状态: 组内无匹配")
                        # 记录第一个有效的票据城市名称作为参考
                        for city in ticket_cities:
                            if pd.notna(city):
                                ticket_city = city
                                break
                    # 检查开票日期是否早于出发时间
                    if not tickets.empty:
                        ticket_date = tickets['开票日期'].min()
                        if pd.notnull(row['出发时间']) and pd.notnull(ticket_date):
                            if ticket_date < row['出发时间']:
                                date_early = True

                    # 如果有任何问题，添加到结果中
                    if city_mismatch or date_early:
                        # 只在需要添加到结果时才计算目的地等级
                        if destination_counts is None:
                            # 计算该组内每个目的地的出现次数
                            destination_counts = pd.DataFrame(group['目的地名称'].value_counts()).reset_index()
                            destination_counts.columns = ['目的地名称', '出现次数']
                            destination_counts['目的地等级'] = destination_counts['出现次数'].map(
                                lambda x: '一级' if x == 1 else '二级'
                            )

                        # 获取当前记录的目的地等级
                        current_level = destination_counts[
                            destination_counts['目的地名称'] == row['目的地名称']
                        ]['目的地等级'].iloc[0] if not pd.isna(row['目的地名称']) else None
                        
                        # 立即打印问题记录
                        print(f"\n发现问题记录:")
                        print(f"人员名称: {row['人员名称']}")
                        print(f"出发时间: {format_datetime(row['出发时间'])}")
                        print(f"目的地: {row['目的地名称']}")
                        print(f"目的地等级: {current_level}")
                        if city_mismatch:
                            print("问题: 城市名称不匹配")
                            print(f"票据城市: {ticket_city}")
                        if date_early:
                            print("问题: 开票日期早于出发时间")
                            print(f"开票日期: {format_datetime(ticket_date)}")
                        print("-" * 50)
                        
                        result_row = row.copy()
                        result_row['城市名称不匹配'] = '是' if city_mismatch else '否'
                        result_row['开票日期早于出发时间'] = '是' if date_early else '否'
                        result_row['票据城市名称'] = ticket_city
                        result_row['开票日期'] = ticket_date
                        result_row['目的地等级'] = current_level
                        result_rows.append(result_row)

        if result_rows:
            # 创建结果DataFrame
            result_df = pd.DataFrame(result_rows)
            
            # 过滤掉问题类型是城市名称不匹配，但城市名称或目的地名称为空的行
            result_df = result_df[
                ~(
                    (result_df['城市名称不匹配'] == '是') & 
                    (
                        result_df['票据城市名称'].isna() | 
                        result_df['目的地名称'].isna()
                    )
                )
            ]
            
            # 对结果进行排序（先按目的地等级排序，一级优先）
            sort_columns = ['目的地等级', '唯一标识', '人员名称', '出发时间']
            result_df = result_df.sort_values(
                by=sort_columns,
                key=lambda x: x.map({'一级': 0, '二级': 1}) if x.name == '目的地等级' else x
            )
            
            # 格式化时间列，只保留年月日
            time_columns = ['出发时间', '到达时间', '开票日期']
            for col in time_columns:
                if col in result_df.columns:
                    result_df[col] = result_df[col].apply(format_datetime)
            
            # 保存结果
            output_file = alldata_dir / "出差目的地变更分析结果.xlsx"
            print(f"正在保存分析结果到: {output_file}")
            
            # 保存为Excel文件
            result_df.to_excel(output_file, index=False)
            if once:
                return result_df
            print("分析完成！")
            
            # 打印统计信息
            total_cases = len(result_df)
            total_employees = len(result_df['人员名称'].unique())
            print(f"\n统计信息:")
            print(f"发现问题记录数: {total_cases}")
            print(f"涉及人员数: {total_employees}")
            
            # 打印各类问题的统计
            print("\n问题类型统计:")
            city_mismatch_count = len(result_df[result_df['城市名称不匹配'] == '是'])
            date_early_count = len(result_df[result_df['开票日期早于出发时间'] == '是'])
            print(f"城市名称不匹配: {city_mismatch_count}条")
            print(f"开票日期早于出发时间: {date_early_count}条")
            
            # 打印详细的问题分布
            print("\n问题详细分布:")
            only_city_mismatch = len(result_df[(result_df['城市名称不匹配'] == '是') & (result_df['开票日期早于出发时间'] == '否')])
            only_date_early = len(result_df[(result_df['城市名称不匹配'] == '否') & (result_df['开票日期早于出发时间'] == '是')])
            both_issues = len(result_df[(result_df['城市名称不匹配'] == '是') & (result_df['开票日期早于出发时间'] == '是')])
            print(f"仅城市名称不匹配: {only_city_mismatch}条")
            print(f"仅开票日期早于出发时间: {only_date_early}条")
            print(f"同时存在两种问题: {both_issues}条")
            
            # 打印目的地等级统计
            level_stats = result_df['目的地等级'].value_counts()
            print("\n目的地等级统计:")
            for level, count in level_stats.items():
                print(f"{level}: {count}条")
            
        else:
            print("未发现问题数据。")
        
        return True
        
    except Exception as e:
        print(f"处理过程中出现错误: {str(e)}")
        traceback.print_exc()  # 打印完整的错误堆栈
        return False

if __name__ == "__main__":
    main()